<?php
namespace Console\Core;

/**
 * Swoole_mysql连接池
 *
 * Class MysqlPool
 * @package Console\Core
 */
class MysqlPool
{
    /**
     * @var array 连接池数组
     */
    protected $_connections;
    /**
     * @var int 最大连接数
     */
    protected $_max;
    /**
     * @var int 最小连接数
     */
    protected $_min;
    /**
     * @var int 已连接数
     */
    protected $_count = 0;
    protected $_inited = false;
    /**
     * @var array sql执行的结果集
     */
    protected $results = [];
    /**
     * @var int sql建立的key
     */
    protected $resultKey = 0;

    /**
     * @var object 实例化类
     */
    private static $instance;
    /**
     * @var array 数据库配置
     */
    protected $config = [
        'host'     => '47.106.132.249',
        'port'     => 3306,
        'user'     => 'dshc',
        'password' => 'daishuhaoche2017',
        'database' => 'dstest',
        'charset'  => 'utf8',
        'timeout'  => 2,
    ];

    public function __construct()
    {
        //初始化连接是一个Spl队列
        $this->_connections = new \SplQueue();
        $this->_max         = 30;
        $this->_min         = 5;
        //绑定单列模式
        self::$instance = &$this;
    }

    /**
     *worker进程启动的时候建立min个连接
     *
     * @return $this|void
     * @throws \Swoole\Mysql\Exception
     */
    public function init()
    {
        if ($this->_inited) {
            return;
        }
        for ($i = 0; $i < $this->_min; $i++) {
            $this->generate();
        }
        return $this;
    }

    /**
     * 建立一个新的连接
     * @throws \Swoole\Mysql\Exception
     */
    public function generate()
    {
        $db = new \swoole_mysql();
        $db->connect($this->config, function ($db, $res)
        {
            if ($res == false) {
                throw new \Exception("数据库连接错误::" . $db->connect_errno . $db->error);
            }
            $this->_count++;
            $this->addConnections($db);
        });
    }

    /**
     * 连接投入队列
     *
     * @param $db
     *
     * @return $this
     */
    public function addConnections($db)
    {
        $this->_connections->push($db);
        return $this;
    }

    /**
     * 维持当前的连接不断线，并且剔除断线的连接
     */
    public function keepAlive()
    {
        // 2分钟检测一次连接
        swoole_timer_tick(1 * 300, function ()
        {
            //维持连接
            while ($this->_connections->count() > 0 && $next = $this->_connections->shift()) {
                $next->query('select 1', function ($db, $res)
                {
                    if ($res == false) {
                        return;
                    }
                    $this->_connections->push($db);
                });
            }
        });

        swoole_timer_tick(1000, function ()
        {
            //维持活跃度的连接数在min-max之间
            if ($this->_connections->count() > $this->_max) {
                while ($this->_max < $this->_connections->count()) {
                    $next = $this->_connections->shift();
                    $next->close();
                    $this->_count--;
                    echo "关闭连接...\n";
                }
            }
        });
    }

    /**
     * 执行数据库命令 . 会判断连接数够不够，够就直接执行，不够就新建连接执行
     *
     * @param $query
     *
     * @return int
     * @throws \Swoole\Mysql\Exception
     */
    public function query($query)
    {
        $key = $this->resultKey++;
        if ($this->_connections->count() == 0) {
            $db = new \swoole_mysql();
            $db->connect($this->config, function ($db, $res) use ($query, $key)
            {
                if ($res == false) {
                    throw new \Exception("数据库连接错误::" . $db->connect_errno . $db->connect_error);
                }
                $this->_count++;
                $db->query($query, function ($db, $result) use ($key)
                {
                    $this->addConnections($db);
                    $this->resultKey[$key] = $result;
                });
            });
        } else {
            $db = $this->_connections->shift();
            $db->query($query, function ($db, $result) use ($key)
            {
                $this->addConnections($db);
                $this->results[$key] = $result;
            });
        }
        return $key;
    }

    /**
     * 获取结果集
     *
     * @param $key
     *
     * @return mixed|null'
     */
    public function getResult($key)
    {
        if (isset($this->results[$key])) {
            return $this->results[$key];
        }
        return null;
    }

    /**
     * 获取实例
     *
     * @return MysqlPool|object
     */
    public static function getInstance()
    {
        if (is_null(self::$instance)) {
            new MysqlPool();
        }
        return self::$instance;
    }

}
